package git.soulbgm.utils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.util.*;

import static java.time.temporal.ChronoUnit.*;

/**
 * 日期时间的处理工具类
 *
 * @author SoulBGM
 * @date 2023-04-06
 */
public class DateUtil {

    /**
     * 年
     */
    public final static int YEAR = Calendar.YEAR;

    /**
     * 季度
     */
    public final static int QUARTER = 20;

    /**
     * 月
     */
    public final static int MONTH = Calendar.MONTH;

    /**
     * 周
     */
    public final static int WEEK = Calendar.DAY_OF_WEEK;

    /**
     * 日
     */
    public final static int DAY = Calendar.DATE;

    /**
     * 时
     */
    public final static int HOUR = Calendar.HOUR_OF_DAY;

    /**
     * 分
     */
    public final static int MINUTE = Calendar.MINUTE;

    /**
     * 秒
     */
    public final static int SECOND = Calendar.SECOND;

    /**
     * 毫秒
     */
    public final static int MILLISECOND = Calendar.MILLISECOND;

    /**
     * 年累积天
     */
    public final static int DAY_OF_YEAR = Calendar.DAY_OF_YEAR;

    /**
     * 月累积天
     */
    public final static int DAY_OF_MONTH = Calendar.DAY_OF_MONTH;

    /**
     * 年-月-日 时:分:秒.毫秒
     */
    public final static String NORM_DATETIME_MS_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS";

    /**
     * 年-月-日 时:分:秒
     */
    public final static String NORM_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /**
     * 年-月-日 时:分
     */
    public final static String FORMAT_YMD_HM = "yyyy-MM-dd HH:mm";

    /**
     * 月-日 时:分
     */
    public final static String FORMAT_MD_HM = "MM-dd HH:mm";

    /**
     * 年-月-日
     */
    public final static String FORMAT_YMD = "yyyy-MM-dd";

    /**
     * 年-月
     */
    public final static String FORMAT_YM = "yyyy-MM";

    /**
     * 时:分:秒
     */
    public final static String FORMAT_HMS = "HH:mm:ss";

    /**
     * 时:分
     */
    public final static String FORMAT_HM = "HH:mm";

    /**
     * 每个月最大的天数
     */
    protected final static Map<Integer, Integer> MAX_DAY_MAP = new HashMap<>(12);

    /**
     * UTC时区
     */
    public static final TimeZone TIME_ZONE_UTC = TimeZone.getTimeZone("UTC");

    /**
     * DateUtil 使用的默认时区
     */
    private static TimeZone defaultTimeZone = TimeZone.getDefault();

    static {
        MAX_DAY_MAP.put(1, 31);
        MAX_DAY_MAP.put(2, 29);
        MAX_DAY_MAP.put(3, 31);
        MAX_DAY_MAP.put(4, 30);
        MAX_DAY_MAP.put(5, 31);
        MAX_DAY_MAP.put(6, 30);
        MAX_DAY_MAP.put(7, 31);
        MAX_DAY_MAP.put(8, 31);
        MAX_DAY_MAP.put(9, 30);
        MAX_DAY_MAP.put(10, 31);
        MAX_DAY_MAP.put(11, 30);
        MAX_DAY_MAP.put(12, 31);
    }

    /**
     * 2月
     */
    protected final static int TWO_MONTH = 2;

    /**
     * 最大的小时
     */
    protected final static int MAX_HOUR = 23;

    /**
     * 最大的分钟
     */
    protected final static int MAX_MINUTE = 59;

    /**
     * 最大的秒
     */
    protected final static int MAX_SECOND = 59;

    /**
     * 最大的毫秒
     */
    protected final static int MAX_MILLISECOND = 999;

    /**
     * 一周的毫秒数
     */
    protected final static int MILLISECONDS_PER_WEEK = 7 * 24 * 60 * 60 * 1000;

    /**
     * 一日的毫秒数
     */
    protected final static int MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;

    /**
     * 一小时的毫秒数
     */
    protected final static int MILLISECONDS_PER_HOUR = 60 * 60 * 1000;

    /**
     * 一分钟的毫秒数
     */
    protected final static int MILLISECONDS_PER_MINUTE = 60 * 1000;

    /**
     * 一秒钟的毫秒数
     */
    protected final static int MILLISECONDS_PER_SECOND = 1000;

    /**
     * 判断日期是否合法
     *
     * @param year  年
     * @param month 月
     * @param day   日
     * @return 合法返回true 不合法false
     */
    public static boolean isDateRational(int year, int month, int day) {
        return isDateRational(year, month, day, 0, 0, 0, 0);
    }

    /**
     * 判断日期是否合法
     *
     * @param year        年
     * @param month       月
     * @param day         日
     * @param hour        时
     * @param minute      分
     * @param second      秒
     * @param millisecond 毫秒
     * @return 合法返回true 不合法false
     */
    public static boolean isDateRational(int year, int month, int day, int hour, int minute, int second, int millisecond) {
        if (year == 0 || month == 0 || day == 0) {
            return false;
        }
        boolean flag = hour >= 0 && hour <= MAX_HOUR && minute >= 0 && minute <= MAX_MINUTE && second >= 0 && second <= MAX_SECOND && millisecond >= 0 && millisecond <= MAX_MILLISECOND;
        if (!flag) {
            return false;
        }
        Integer maxDay = getMonthDayNum(month);
        if (maxDay == null) {
            return false;
        }
        if (month == TWO_MONTH && isLeapYear(year)) {
            return day <= maxDay;
        } else {
            return day <= maxDay - 1;
        }
    }

    /**
     * 通过传入月份得到月份的天数
     *
     * @param month 月
     * @return {@link Integer}
     */
    public static Integer getMonthDayNum(int month) {
        if (month < 1 || month > 12) {
            return 0;
        }
        return MAX_DAY_MAP.get(month);
    }

    /**
     * 判断是否为闰年
     *
     * @param year 年
     * @return 是闰年返回true 不是返回false
     */
    public static boolean isLeapYear(int year) {
        return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
    }

    /**
     * 获得现在时间的时间戳
     * 性能低 System.currentTimeMillis();
     *
     * @return 时间戳
     */
    public static long getTimeStamp() {
        return System.currentTimeMillis();
    }

    /**
     * 获得现在时间 Date
     *
     * @return Date
     */
    public static Date getNow() {
        return new Date();
    }

    /**
     * 设置DateUtil类使用的时区
     *
     * @param timeZone 时区
     */
    public static void setTimeZone(TimeZone timeZone) {
        if (timeZone != null) {
            defaultTimeZone = timeZone;
        }
    }

    /**
     * 获得现在时间 Calendar
     *
     * @param timeZone 时区
     * @return {@link Calendar}
     */
    public static Calendar getCalendar(TimeZone timeZone) {
        return Calendar.getInstance(timeZone);
    }

    /**
     * 获得现在时间 Calendar
     *
     * @return Calendar
     */
    public static Calendar getCalendar() {
        return Calendar.getInstance();
    }

    /**
     * 获得现在时间 String
     * 格式：yyyy-MM-dd hh:mm:ss.SSS
     *
     * @return 字符串显示的时间
     */
    public static String getNowStr() {
        return getNowStr(NORM_DATETIME_PATTERN);
    }

    /**
     * 获得现在时间 String
     *
     * @param pattern 时间格式
     * @return 字符串显示的时间
     */
    public static String getNowStr(String pattern) {
        return format(getNow(), pattern);
    }

    /**
     * 获得Calendar对象的年或月等
     *
     * @param calendar Calendar对象
     * @param field    日历字段
     * @return filed对应的值
     */
    public static int getTime(Calendar calendar, int field) {
        if (calendar == null) {
            return 0;
        }
        int time = calendar.get(field);
        if (field == MONTH) {
            return time + 1;
        } else if (field == WEEK) {
            time = time - 1;
            return time == 0 ? 7 : time;
        }
        return time;
    }

    /**
     * 获得Calendar的年
     *
     * @param calendar Calendar对象
     * @return 年
     */
    public static int getYear(Calendar calendar) {
        return getTime(calendar, YEAR);
    }

    /**
     * 获得Calendar的月
     *
     * @param calendar Calendar对象
     * @return 月
     */
    public static int getMonth(Calendar calendar) {
        return getTime(calendar, MONTH);
    }

    /**
     * 获得Calendar的属于周几
     * 1为周一  7为周日
     *
     * @return 周几
     */
    public static int getWeek(Calendar calendar) {
        return getTime(calendar, WEEK);
    }

    /**
     * 获得Calendar的日
     *
     * @return 日
     */
    public static int getDay(Calendar calendar) {
        return getTime(calendar, DAY);
    }

    /**
     * 获得Calendar的小时
     *
     * @return 小时
     */
    public static int getHour(Calendar calendar) {
        return getTime(calendar, HOUR);
    }

    /**
     * 获得Calendar的分钟
     *
     * @return 分钟
     */
    public static int getMinute(Calendar calendar) {
        return getTime(calendar, MINUTE);
    }

    /**
     * 获得Calendar的秒
     *
     * @return 秒
     */
    public static int getSecond(Calendar calendar) {
        return getTime(calendar, SECOND);
    }

    /**
     * 获得Calendar的毫秒
     *
     * @return 毫秒
     */
    public static int getMillisecond(Calendar calendar) {
        return getTime(calendar, MILLISECOND);
    }

    /**
     * 获得年累积天
     *
     * @return 年累积天
     */
    public static int getDayOfYear(Calendar calendar) {
        return getTime(calendar, DAY_OF_YEAR);
    }

    /**
     * 获得月累积天
     *
     * @return 月累积天
     */
    public static int getDayOfMonth(Calendar calendar) {
        return getTime(calendar, DAY_OF_MONTH);
    }

    /**
     * 获取起始日期
     *
     * @param calendar Calendar对象
     * @param field    获取的field
     * @return 返回起始日期
     */
    public static Calendar getStartCalendar(Calendar calendar, int field) {
        if (field == YEAR) {
            calendar.set(MONTH, calendar.getActualMinimum(MONTH));
            calendar.set(DAY, calendar.getActualMinimum(DAY));
            calendar.set(HOUR, calendar.getActualMinimum(HOUR));
            calendar.set(MINUTE, calendar.getActualMinimum(MINUTE));
            calendar.set(SECOND, calendar.getActualMinimum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMinimum(MILLISECOND));
        } else if (field == QUARTER) {
            calendar.set(MONTH, (calendar.get(Calendar.MONTH) / 3) * 3);
            calendar.set(DAY, calendar.getActualMinimum(DAY));
            calendar.set(HOUR, calendar.getActualMinimum(HOUR));
            calendar.set(MINUTE, calendar.getActualMinimum(MINUTE));
            calendar.set(SECOND, calendar.getActualMinimum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMinimum(MILLISECOND));
        } else if (field == MONTH) {
            calendar.set(DAY, calendar.getActualMinimum(DAY));
            calendar.set(HOUR, calendar.getActualMinimum(HOUR));
            calendar.set(MINUTE, calendar.getActualMinimum(MINUTE));
            calendar.set(SECOND, calendar.getActualMinimum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMinimum(MILLISECOND));
        } else if (field == DAY) {
            calendar.set(HOUR, calendar.getActualMinimum(HOUR));
            calendar.set(MINUTE, calendar.getActualMinimum(MINUTE));
            calendar.set(SECOND, calendar.getActualMinimum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMinimum(MILLISECOND));
        } else if (field == HOUR) {
            calendar.set(MINUTE, calendar.getActualMinimum(MINUTE));
            calendar.set(SECOND, calendar.getActualMinimum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMinimum(MILLISECOND));
        } else if (field == MINUTE) {
            calendar.set(SECOND, calendar.getActualMinimum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMinimum(MILLISECOND));
        } else if (field == SECOND) {
            calendar.set(MILLISECOND, calendar.getActualMinimum(MILLISECOND));
        } else if (field == WEEK) {
            if (getWeek(calendar) == 7) {
                calendar.add(DAY, -1);
            }
            calendar.set(WEEK, calendar.getActualMinimum(WEEK) + 1);
            calendar.set(HOUR, calendar.getActualMinimum(HOUR));
            calendar.set(MINUTE, calendar.getActualMinimum(MINUTE));
            calendar.set(SECOND, calendar.getActualMinimum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMinimum(MILLISECOND));
        }
        return calendar;
    }

    public static final String UNIT_QUARTERS = "Quarters";

    /**
     * 获取起始日期
     *
     * @param dateTime LocalDateTime对象
     * @param unit     时间单位
     * @return 返回起始日期
     */
    public static LocalDateTime getStartDateTime(LocalDateTime dateTime, String unit) {
        if (YEARS.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.DAY_OF_YEAR, dateTime.range(ChronoField.DAY_OF_YEAR).getMinimum())
                    .with(ChronoField.MILLI_OF_DAY, dateTime.range(ChronoField.MILLI_OF_DAY).getMinimum());
        } else if (UNIT_QUARTERS.equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.MONTH_OF_YEAR, ((dateTime.getMonthValue() - 1) / 3) * 3 + 1)
                    .with(ChronoField.DAY_OF_MONTH, dateTime.range(ChronoField.DAY_OF_MONTH).getMinimum())
                    .with(ChronoField.MILLI_OF_DAY, dateTime.range(ChronoField.MILLI_OF_DAY).getMinimum());
        } else if (MONTHS.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.DAY_OF_MONTH, dateTime.range(ChronoField.DAY_OF_MONTH).getMinimum())
                    .with(ChronoField.MILLI_OF_DAY, dateTime.range(ChronoField.MILLI_OF_DAY).getMinimum());
        } else if (DAYS.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.MILLI_OF_DAY, dateTime.range(ChronoField.MILLI_OF_DAY).getMinimum());
        } else if (HOURS.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.MINUTE_OF_HOUR, dateTime.range(ChronoField.MINUTE_OF_HOUR).getMinimum())
                    .with(ChronoField.SECOND_OF_MINUTE, dateTime.range(ChronoField.SECOND_OF_MINUTE).getMinimum())
                    .with(ChronoField.MILLI_OF_SECOND, dateTime.range(ChronoField.MILLI_OF_SECOND).getMinimum());
        } else if (MINUTES.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.SECOND_OF_MINUTE, dateTime.range(ChronoField.SECOND_OF_MINUTE).getMinimum())
                    .with(ChronoField.MILLI_OF_SECOND, dateTime.range(ChronoField.MILLI_OF_SECOND).getMinimum());
        } else if (SECONDS.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.MILLI_OF_SECOND, dateTime.range(ChronoField.MILLI_OF_SECOND).getMinimum());
        } else if (WEEKS.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.DAY_OF_WEEK, dateTime.range(ChronoField.DAY_OF_WEEK).getMinimum())
                    .with(ChronoField.MILLI_OF_DAY, dateTime.range(ChronoField.MILLI_OF_DAY).getMinimum());
        }
        return dateTime;
    }

    /**
     * 获取末尾日期
     *
     * @param calendar Calendar对象
     * @param field    获取的field
     * @return 返回末尾日期
     */
    public static Calendar getEndCalendar(Calendar calendar, int field) {
        if (field == YEAR) {
            calendar.set(MONTH, calendar.getActualMaximum(MONTH));
            calendar.set(DAY, calendar.getActualMaximum(DAY));
            calendar.set(HOUR, calendar.getActualMaximum(HOUR));
            calendar.set(MINUTE, calendar.getActualMaximum(MINUTE));
            calendar.set(SECOND, calendar.getActualMaximum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMaximum(MILLISECOND));
        } else if (field == QUARTER) {
            calendar.set(MONTH, (calendar.get(MONTH) + 3) / 3 * 3 - 1);
            calendar.set(DAY, calendar.getActualMaximum(DAY));
            calendar.set(HOUR, calendar.getActualMaximum(HOUR));
            calendar.set(MINUTE, calendar.getActualMaximum(MINUTE));
            calendar.set(SECOND, calendar.getActualMaximum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMaximum(MILLISECOND));
        } else if (field == MONTH) {
            calendar.set(DAY, calendar.getActualMaximum(DAY));
            calendar.set(HOUR, calendar.getActualMaximum(HOUR));
            calendar.set(MINUTE, calendar.getActualMaximum(MINUTE));
            calendar.set(SECOND, calendar.getActualMaximum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMaximum(MILLISECOND));
        } else if (field == DAY) {
            calendar.set(HOUR, calendar.getActualMaximum(HOUR));
            calendar.set(MINUTE, calendar.getActualMaximum(MINUTE));
            calendar.set(SECOND, calendar.getActualMaximum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMaximum(MILLISECOND));
        } else if (field == HOUR) {
            calendar.set(MINUTE, calendar.getActualMaximum(MINUTE));
            calendar.set(SECOND, calendar.getActualMaximum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMaximum(MILLISECOND));
        } else if (field == MINUTE) {
            calendar.set(SECOND, calendar.getActualMaximum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMaximum(MILLISECOND));
        } else if (field == SECOND) {
            calendar.set(MILLISECOND, calendar.getActualMaximum(MILLISECOND));
        } else if (field == WEEK) {
            if (getWeek(calendar) == 7) {
                calendar.add(DAY, -1);
            }
            calendar.set(WEEK, calendar.getActualMaximum(WEEK));
            calendar.add(DAY, 1);
            calendar.set(HOUR, calendar.getActualMaximum(HOUR));
            calendar.set(MINUTE, calendar.getActualMaximum(MINUTE));
            calendar.set(SECOND, calendar.getActualMaximum(SECOND));
            calendar.set(MILLISECOND, calendar.getActualMaximum(MILLISECOND));
        }
        return calendar;
    }

    /**
     * 获取末尾日期
     *
     * @param dateTime LocalDateTime对象
     * @param unit     时间单位
     * @return 返回末尾日期
     */
    public static LocalDateTime getEndDateTime(LocalDateTime dateTime, String unit) {
        if (YEARS.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.DAY_OF_YEAR, dateTime.range(ChronoField.DAY_OF_YEAR).getMaximum())
                    .with(ChronoField.MILLI_OF_DAY, dateTime.range(ChronoField.MILLI_OF_DAY).getMaximum());
        } else if (UNIT_QUARTERS.equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.MONTH_OF_YEAR, ((dateTime.getMonthValue() - 1) / 3) * 3 + 3)
                    .with(ChronoField.DAY_OF_MONTH, dateTime.range(ChronoField.DAY_OF_MONTH).getMaximum())
                    .with(ChronoField.MILLI_OF_DAY, dateTime.range(ChronoField.MILLI_OF_DAY).getMaximum());
        } else if (MONTHS.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.DAY_OF_MONTH, dateTime.range(ChronoField.DAY_OF_MONTH).getMaximum())
                    .with(ChronoField.MILLI_OF_DAY, dateTime.range(ChronoField.MILLI_OF_DAY).getMaximum());
        } else if (DAYS.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.MILLI_OF_DAY, dateTime.range(ChronoField.MILLI_OF_DAY).getMaximum());
        } else if (HOURS.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.MINUTE_OF_HOUR, dateTime.range(ChronoField.MINUTE_OF_HOUR).getMaximum())
                    .with(ChronoField.SECOND_OF_MINUTE, dateTime.range(ChronoField.SECOND_OF_MINUTE).getMaximum())
                    .with(ChronoField.MILLI_OF_SECOND, dateTime.range(ChronoField.MILLI_OF_SECOND).getMaximum());
        } else if (MINUTES.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.SECOND_OF_MINUTE, dateTime.range(ChronoField.SECOND_OF_MINUTE).getMaximum())
                    .with(ChronoField.MILLI_OF_SECOND, dateTime.range(ChronoField.MILLI_OF_SECOND).getMaximum());
        } else if (SECONDS.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.MILLI_OF_SECOND, dateTime.range(ChronoField.MILLI_OF_SECOND).getMaximum());
        } else if (WEEKS.toString().equalsIgnoreCase(unit)) {
            return dateTime.with(ChronoField.DAY_OF_WEEK, dateTime.range(ChronoField.DAY_OF_WEEK).getMaximum())
                    .with(ChronoField.MILLI_OF_DAY, dateTime.range(ChronoField.MILLI_OF_DAY).getMaximum());
        }
        return dateTime;
    }

    /**
     * 设置时间（年月日时分秒毫秒）
     *
     * @param year   年
     * @param month  月
     * @param day    日
     * @param hour   时
     * @param minute 分
     * @param second 秒
     * @return Calendar
     */
    public static Calendar setCalendar(int year, int month, int day, int hour, int minute, int second) {
        Calendar calendar = getCalendar();
        calendar.set(year, month - 1, day, hour, minute, second);
        return calendar;
    }

    /**
     * 设置时间（年月日）
     *
     * @param year  年
     * @param month 月
     * @param day   日
     * @return Calendar
     */
    public static Calendar setCalendar(int year, int month, int day) {
        Calendar calendar = getCalendar();
        calendar.set(year, month - 1, day);
        return calendar;
    }

    /**
     * 通过时间戳获得Calendar对象
     *
     * @param timeStamp 时间戳
     * @return Calendar对象
     */
    public static Calendar getCalendar(long timeStamp) {
        return getCalendar(new Date(timeStamp));
    }

    /**
     * 通过Date对象获得Calendar对象
     *
     * @param date Date对象
     * @return Calendar对象
     */
    public static Calendar getCalendar(Date date) {
        Calendar calendar = getCalendar();
        calendar.setTime(date);
        return calendar;
    }

    /**
     * 设置时间（年月日时分秒毫秒）
     *
     * @param year        年
     * @param month       月
     * @param day         日
     * @param hour        时
     * @param minute      分
     * @param second      秒
     * @param millisecond 毫秒
     * @return Calendar
     */
    public static Calendar getCalendar(int year, int month, int day, int hour, int minute, int second, int millisecond) {
        Calendar calendar = getCalendar();
        calendar.set(year, month - 1, day, hour, minute, second);
        calendar.set(Calendar.MILLISECOND, millisecond);
        return calendar;
    }

    /**
     * 设置时间（年月日）时分秒毫秒归零
     *
     * @param year  年
     * @param month 月
     * @param day   日
     * @return Calendar
     */
    public static Calendar getCalendar(int year, int month, int day) {
        return getCalendar(year, month, day, 0, 0, 0, 0);
    }

    /**
     * 设置时间（年 年积日）时分秒毫秒归零
     *
     * @param year      年
     * @param dayOfYear 年积日
     * @return Calendar
     */
    public static Calendar getCalendar(int year, int dayOfYear) {
        Calendar calendar = getStartCalendar(getCalendar(), DAY);
        calendar.set(YEAR, year);
        calendar.set(DAY_OF_YEAR, dayOfYear);
        return calendar;
    }

    /**
     * 设置时间（年月日时分秒）毫秒归零
     *
     * @param year   年
     * @param month  月
     * @param day    日
     * @param hour   时
     * @param minute 分
     * @param second 秒
     * @return Calendar
     */
    public static Calendar getCalendar(int year, int month, int day, int hour, int minute, int second) {
        return getCalendar(year, month, day, hour, minute, second, 0);
    }

    /**
     * 偏移日期
     * 整数就增加日期 负数就减少日期
     *
     * @param calendar Calendar对象
     * @param field    偏移的日历字段 YEAR MONTH ...
     * @param amount   偏移的数值
     * @return Calendar对象
     */
    public static Calendar offsetDate(Calendar calendar, int field, int amount) {
        if (calendar == null) {
            return null;
        }
        calendar.add(field, amount);
        return calendar;
    }

    /**
     * 偏移日期
     * 整数就增加日期 负数就减少日期
     *
     * @param dateTime 日期时间
     * @param unit     时间单位
     * @param amount   偏移的数值
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime offsetDate(LocalDateTime dateTime, ChronoUnit unit, long amount) {
        if (dateTime == null) {
            return null;
        }
        return dateTime.plus(amount, unit);
    }

    /**
     * 偏移日期
     * 整数就增加日期 负数就减少日期
     *
     * @param dateTime 日期时间
     * @param unit     时间单位
     * @param amount   偏移的数值
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime offsetDate(LocalDateTime dateTime, String unit, long amount) {
        if (dateTime == null) {
            return null;
        }
        if (YEARS.toString().equalsIgnoreCase(unit)) {
            return dateTime.plus(amount, YEARS);
        } else if (UNIT_QUARTERS.equalsIgnoreCase(unit)) {
            return dateTime.plus(amount * 3L, MONTHS);
        } else if (MONTHS.toString().equalsIgnoreCase(unit)) {
            return dateTime.plus(amount, MONTHS);
        } else if (DAYS.toString().equalsIgnoreCase(unit)) {
            return dateTime.plus(amount, DAYS);
        } else if (HOURS.toString().equalsIgnoreCase(unit)) {
            return dateTime.plus(amount, HOURS);
        } else if (MINUTES.toString().equalsIgnoreCase(unit)) {
            return dateTime.plus(amount, MINUTES);
        } else if (SECONDS.toString().equalsIgnoreCase(unit)) {
            return dateTime.plus(amount, SECONDS);
        } else if (WEEKS.toString().equalsIgnoreCase(unit)) {
            return dateTime.plus(amount, WEEKS);
        } else if (MILLIS.toString().equalsIgnoreCase(unit)) {
            return dateTime.plus(amount, MILLIS);
        }
        throw new RuntimeException("无法识别 " + unit + " 时间单位");
    }

    /**
     * 获得时间轴列表
     * 例:假如需要获得最近24小时的时间轴列表则如下给参数
     * getTimeAxis(DateUtil.getCalendar(), DateUtil.HOUR, 24, true);
     *
     * @param endCalendar 结束时间
     * @param filed       需要偏移的字段 取值在DateUtil中 如DateUtil.HOUR
     * @param amount      需要的偏移多长时间
     * @param flag        是否保留结束时间
     * @return 时间轴列表
     */
    public static List<Calendar> getTimeAxis(Calendar endCalendar, int filed, int amount, boolean flag) {
        return getTimeAxis(endCalendar, filed, amount, 1, flag);
    }

    /**
     * 获得时间轴列表
     * 例:假如需要获得最近24小时的时间轴列表则如下给参数
     * getTimeAxis(DateUtil.getCalendar(), DateUtil.HOUR, 24, true);
     *
     * @param endCalendar    结束时间
     * @param filed          需要偏移的字段 取值在DateUtil中 如DateUtil.HOUR
     * @param amount         需要的偏移多长时间
     * @param amountMultiple 每次偏移的倍数
     * @param flag           是否保留结束时间
     * @return 时间轴列表
     */
    public static List<Calendar> getTimeAxis(Calendar endCalendar, int filed, int amount, int amountMultiple, boolean flag) {
        if (isNull(endCalendar)) {
            return new ArrayList<>(0);
        }
        List<Calendar> list = new ArrayList<>(amount);
        //Calendar newEndCalender = getStartCalendar(endCalendar, filed);
        Calendar newEndCalender = endCalendar;
        int offset;
        int stepSize = amountMultiple;
        if (filed == WEEK) {
            filed = DAY;
            stepSize = 7 * amountMultiple;
        }
        offset = stepSize * amount;
        if (flag) {
            offset = offset - stepSize;
        }
        Calendar startCalender = DateUtil.offsetDate(newEndCalender, filed, -offset);
        if (startCalender == null) {
            return list;
        }
        long time = startCalender.getTimeInMillis();
        for (int i = 0; i < amount; i++) {
            Calendar calendar = getCalendar(time);
            offsetDate(calendar, filed, stepSize * i);
            list.add(calendar);
        }
        return list;
    }

    /**
     * 将日历列表转换为给定的日期格式字符串
     *
     * @param list      日历列表
     * @param formatter 日期格式对象
     * @return {@link List}<{@link String}>
     */
    public static List<String> convert(List<Calendar> list, DateTimeFormatter formatter) {
        if (list == null || formatter == null) {
            return Collections.emptyList();
        }
        List<String> dateList = new ArrayList<>(list.size());
        for (Calendar c : list) {
            dateList.add(format(c.getTimeInMillis(), formatter));
        }
        return dateList;
    }

    /*
        // 按分钟
        System.out.println("按分钟 最近60秒");
        Calendar endCalendar = DateUtil.getCalendar();
        endCalendar = DateUtil.getStartCalendar(endCalendar, DateUtil.MINUTE);
        List<Calendar> calendarList = DateUtil.getTimeAxis(endCalendar, DateUtil.SECOND, 6, 10, true);
        for (Calendar calendar : calendarList) {
            System.out.println(format(calendar.getTime(), DateUtil.FORMAT_YMD_HMS));
        }

        // 按小时
        System.out.println("按小时 最近30分钟");
        endCalendar = DateUtil.getStartCalendar(endCalendar, DateUtil.MINUTE);
        calendarList = DateUtil.getTimeAxis(endCalendar, DateUtil.MINUTE, 60, 1, true);
        for (Calendar calendar : calendarList) {
            System.out.println(format(calendar.getTime(), DateUtil.FORMAT_YMD_HMS));
        }

        // 按天
        System.out.println("按天 最近的24小时");
        endCalendar = DateUtil.getStartCalendar(endCalendar, DateUtil.MINUTE);
        calendarList = DateUtil.getTimeAxis(endCalendar, DateUtil.HOUR, 24, 1, true);
        for (Calendar calendar : calendarList) {
            System.out.println(format(calendar.getTime(), DateUtil.FORMAT_YMD_HMS));
        }

        // 按周
        System.out.println("按周 最近的7天");
        endCalendar = DateUtil.getStartCalendar(endCalendar, DateUtil.MINUTE);
        calendarList = DateUtil.getTimeAxis(endCalendar, DateUtil.DAY, 7, 1, true);
        for (Calendar calendar : calendarList) {
            System.out.println(format(calendar.getTime(), DateUtil.FORMAT_YMD_HMS));
        }

        // 按月
        System.out.println("按月 最30天");
        endCalendar = DateUtil.getStartCalendar(endCalendar, DateUtil.MINUTE);
        calendarList = DateUtil.getTimeAxis(endCalendar, DateUtil.DAY, 30, 1, true);
        for (Calendar calendar : calendarList) {
            System.out.println(format(calendar.getTime(), DateUtil.FORMAT_YMD_HMS));
        }

    */

    public static boolean isNull(Calendar... calendars) {
        for (Calendar calendar : calendars) {
            if (calendar == null) {
                return true;
            }
        }
        return false;
    }

    public static boolean isNotNull(Calendar... calendars) {
        for (Calendar calendar : calendars) {
            if (calendar == null) {
                return false;
            }
        }
        return true;
    }

    /**
     * 日期比较 大于并且小于
     * comparisonCalendar > startCalendar && comparisonCalendar < endCalendar
     *
     * @param comparisonCalendar 比较的日期
     * @param startCalendar      开始日期
     * @param endCalendar        结束日期
     * @return 符合条件为true 否则 false
     */
    public static boolean whetherExceedAndLessThan(Calendar comparisonCalendar, Calendar startCalendar, Calendar endCalendar) {
        if (isNull(comparisonCalendar, startCalendar, endCalendar)) {
            return false;
        }
        return comparisonCalendar.after(startCalendar) && comparisonCalendar.before(endCalendar);
    }

    /**
     * 日期比较 大于等于并且小于等于
     * comparisonCalendar > startCalendar && comparisonCalendar < endCalendar
     *
     * @param comparisonCalendar 比较的日期
     * @param startCalendar      开始日期
     * @param endCalendar        结束日期
     * @return 符合条件为true 否则 false
     */
    public static boolean whetherExceedEqualsAndLessThanEquals(Calendar comparisonCalendar, Calendar startCalendar, Calendar endCalendar) {
        if (isNull(comparisonCalendar, startCalendar, endCalendar)) {
            return false;
        }
        return (comparisonCalendar.after(startCalendar) || comparisonCalendar.equals(startCalendar)) && (comparisonCalendar.before(endCalendar) || comparisonCalendar.equals(endCalendar));
    }

    /**
     * 日期比较 大于
     * comparisonCalendar > startCalendar
     *
     * @param comparisonCalendar 比较的日期
     * @param calendar           日期
     * @return 符合条件为true 否则 false
     */
    public static boolean whetherExceed(Calendar comparisonCalendar, Calendar calendar) {
        if (isNull(comparisonCalendar, calendar)) {
            return false;
        }
        return comparisonCalendar.after(calendar);
    }

    /**
     * 日期比较 大于等于
     * comparisonCalendar > startCalendar
     *
     * @param comparisonCalendar 比较的日期
     * @param calendar           日期
     * @return 符合条件为true 否则 false
     */
    public static boolean whetherExceedEquals(Calendar comparisonCalendar, Calendar calendar) {
        if (isNull(comparisonCalendar, calendar)) {
            return false;
        }
        return comparisonCalendar.after(calendar) || comparisonCalendar.equals(calendar);
    }

    /**
     * 日期比较 小于
     * comparisonCalendar < endCalendar
     *
     * @param comparisonCalendar 比较的日期
     * @param calendar           日期
     * @return 符合条件为true 否则 false
     */
    public static boolean whetherLessThan(Calendar comparisonCalendar, Calendar calendar) {
        if (isNull(comparisonCalendar, calendar)) {
            return false;
        }
        return comparisonCalendar.before(calendar);
    }

    /**
     * 日期比较 小于等于
     * comparisonCalendar < endCalendar
     *
     * @param comparisonCalendar 比较的日期
     * @param calendar           日期
     * @return 符合条件为true 否则 false
     */
    public static boolean whetherLessThanEquals(Calendar comparisonCalendar, Calendar calendar) {
        if (isNull(comparisonCalendar, calendar)) {
            return false;
        }
        return comparisonCalendar.before(calendar) || comparisonCalendar.equals(calendar);
    }

    /**
     * 获取时间戳
     *
     * @param dateTime 日期时间
     * @return long
     */
    public static long getTimestamp(LocalDateTime dateTime) {
        return getTimestamp(dateTime, ZoneId.systemDefault());
    }

    /**
     * 获取时间戳
     *
     * @param dateTime 日期时间
     * @param zone     时区
     * @return long
     */
    public static long getTimestamp(LocalDateTime dateTime, ZoneId zone) {
        return dateTime.atZone(zone).toInstant().toEpochMilli();
    }

    /**
     * 获取当前日期时间
     *
     * @return {@link String}
     */
    public static String getCurrentDateTime(DateTimeFormatter formatter) {
        return format(getDateTime(), formatter);
    }

    /**
     * 获取当前日期时间
     *
     * @return {@link String}
     */
    public static String getCurrentDateTime() {
        return getCurrentDateTime(NORM_DATETIME_MS_FORMATTER);
    }

    /**
     * 获取日期时间
     *
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime getDateTime() {
        return LocalDateTime.now();
    }

    /**
     * 获取日期时间
     *
     * @param timestamp 时间戳
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime getDateTime(long timestamp) {
        return getDateTime(timestamp, ZoneId.systemDefault());
    }

    /**
     * 获取日期时间
     *
     * @param timestamp 时间戳
     * @param zone      时区
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime getDateTime(long timestamp, ZoneId zone) {
        return Instant.ofEpochMilli(timestamp).atZone(zone).toLocalDateTime();
    }

    /**
     * 标准日期时间格式，精确到毫秒：yyyy-MM-dd HH:mm:ss.SSS
     */
    public static final DateTimeFormatter NORM_DATETIME_MS_FORMATTER = createFormatter(NORM_DATETIME_MS_PATTERN);

    /**
     * 创建并为 {@link DateTimeFormatter} 赋予默认时区和位置信息，默认值为系统默认值。
     *
     * @param pattern 日期格式
     * @return {@link DateTimeFormatter}
     */
    public static DateTimeFormatter createFormatter(String pattern) {
        return createFormatter(pattern, ZoneId.systemDefault());
    }

    /**
     * 创建并为 {@link DateTimeFormatter} 赋予默认时区和位置信息，默认值为系统默认值。
     *
     * @param pattern 日期格式
     * @return {@link DateTimeFormatter}
     */
    public static DateTimeFormatter createFormatter(String pattern, ZoneId zone) {
        return DateTimeFormatter.ofPattern(pattern, Locale.getDefault()).withZone(zone);
    }

    /**
     * 解析
     *
     * @param dateTime 日期时间
     * @param zone     时区
     * @return {@link Date}
     */
    public static Date convert(LocalDateTime dateTime, ZoneId zone) {
        return Date.from(dateTime.atZone(zone).toInstant());
    }

    /**
     * 解析
     *
     * @param date 日期
     * @param zone 时区
     * @return {@link Date}
     */
    public static Date convert(LocalDate date, ZoneId zone) {
        return Date.from(date.atStartOfDay(zone).toInstant());
    }

    /**
     * 解析
     *
     * @param dateStr   日期字符串
     * @param formatter 格式化程序
     * @param zone      时区
     * @return {@link Date}
     */
    public static Date parse(String dateStr, DateTimeFormatter formatter, ZoneId zone) {
        TemporalAccessor temporalAccessor = formatter.parseBest(dateStr, LocalDateTime::from, LocalDate::from, LocalTime::from);
        if (temporalAccessor instanceof LocalDateTime) {
            LocalDateTime dateTime = LocalDateTime.from(temporalAccessor);
            return DateUtil.convert(dateTime, zone);
        } else if (temporalAccessor instanceof LocalDate) {
            LocalDate localDate = LocalDate.from(temporalAccessor);
            return DateUtil.convert(localDate, zone);
        } else if (temporalAccessor instanceof LocalTime) {
            LocalTime localTime = LocalTime.from(temporalAccessor);
            LocalDate localDate = LocalDate.now();
            return DateUtil.convert(LocalDateTime.of(localDate, localTime), zone);
        }
        throw new RuntimeException("格式有误");
    }

    /**
     * 解析
     *
     * @param dateStr   日期字符串
     * @param formatter 格式化程序
     * @return {@link Date}
     */
    public static Date parse(String dateStr, DateTimeFormatter formatter) {
        return parse(dateStr, formatter, ZoneId.systemDefault());
    }

    /**
     * 解析
     *
     * @param dateStr 日期字符串
     * @param pattern 时间格式
     * @return {@link Date}
     */
    public static Date parse(String dateStr, String pattern) {
        return parse(dateStr, createFormatter(pattern));
    }

    /**
     * 解析 yyyy-MM-dd HH:mm:ss.SSS格式时间字符串
     *
     * @param dateStr 日期字符串
     * @return {@link Date}
     */
    public static Date parse(String dateStr) {
        return parse(dateStr, NORM_DATETIME_MS_FORMATTER);
    }

    /**
     * 解析日期时间
     *
     * @param dateStr   日期字符串
     * @param formatter 格式化程序
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime parseDateTime(String dateStr, DateTimeFormatter formatter) {
        return LocalDateTime.from(formatter.parse(dateStr));
    }

    /**
     * 解析日期时间
     *
     * @param dateStr 日期字符串
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime parseDateTime(String dateStr) {
        return LocalDateTime.from(NORM_DATETIME_MS_FORMATTER.parse(dateStr));
    }

    /**
     * 格式
     *
     * @param timestamp 时间戳
     * @param formatter 格式化程序
     * @return {@link String}
     */
    public static String format(Long timestamp, DateTimeFormatter formatter) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        LocalDateTime dateTime = LocalDateTime.ofInstant(instant, formatter.getZone());
        return format(dateTime, formatter);
    }

    /**
     * 格式
     *
     * @param dateTime  日期时间
     * @param formatter 格式化程序
     * @return {@link String}
     */
    public static String format(LocalDateTime dateTime, DateTimeFormatter formatter) {
        return formatter.format(dateTime);
    }

    /**
     * 格式
     *
     * @param dateTime 日期时间
     * @return {@link String}
     */
    public static String format(LocalDateTime dateTime) {
        return NORM_DATETIME_MS_FORMATTER.format(dateTime);
    }

    /**
     * 格式
     *
     * @param timestamp 时间戳
     * @return {@link String}
     */
    public static String format(Long timestamp) {
        return format(timestamp, NORM_DATETIME_MS_FORMATTER);
    }

    /**
     * 格式
     *
     * @param date    日期
     * @param pattern 时间格式
     * @return {@link String}
     */
    public static String format(Date date, String pattern) {
        return format(date.getTime(), createFormatter(pattern));
    }

}
